# 在高德地图上显示照片的坐标位置
# xiaoyf 编写
# pyinstaller -F d:\pythonp\wx2\view_jpg_gps_map.py
# pyinstaller -F view_jpg_gps_map.py
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple coordTransform
# pip install  coordTransform_py
# pip install Pillow
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Pillow
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple rawpy
# pip install -i https://pypi.tuna.tsinghua.edu.cn/simple exifread

import wx
import wx.html
import wx.html2
import os
from PIL import Image
from PIL.ExifTags import TAGS
import rawpy
from fractions import Fraction
import exifread
import subprocess  # 用于调用 exiftool
import exiftool
#import coordtransform
import requests
import json
# 导入高德地图配置参数 api_key
import gd_config
import re
import subprocess


class MyFramemap(wx.Frame):
    def __init__(self):
        super().__init__(None, title='照片GPS位置信息，高德地图查看器', size=(900, 800))

        panel = wx.Panel(self)
        vbox = wx.BoxSizer(wx.VERTICAL)

        # 第一行：输入框和按钮
        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.input_box = wx.TextCtrl(panel)
        self.select_btn = wx.Button(panel, label='选择照片目录')
        self.select_btn.Bind(wx.EVT_BUTTON, self.on_select_directory)

        self.exit_btn = wx.Button(panel, label='退出')
        self.exit_btn.Bind(wx.EVT_BUTTON, self.on_exit)

        hbox1.Add(self.input_box, proportion=1, flag=wx.EXPAND)
        hbox1.Add(self.select_btn, flag=wx.LEFT, border=5)
        hbox1.Add(self.exit_btn, flag=wx.LEFT, border=5)

        vbox.Add(hbox1, flag=wx.EXPAND | wx.ALL, border=10)

        # 第二行：文件列表
        self.file_list = wx.ListBox(panel)
        self.file_list.Bind(wx.EVT_LISTBOX, self.on_select_photo)  # 绑定选中事件
        vbox.Add(self.file_list, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)

        # 第三行：显示地图
        #self.map_window = wx.html.HtmlWindow(panel)
        self.map_window = wx.html2.WebView.New(panel)
        vbox.Add(self.map_window, proportion=3, flag=wx.EXPAND | wx.ALL, border=10)

        panel.SetSizer(vbox)
        self.Show()

    def on_exit(self, event):
        self.Close()  # 关闭窗口

    def on_select_directory(self, event):
        with wx.DirDialog(self, "选择照片目录") as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                directory = dialog.GetPath()
                self.input_box.SetValue(directory)
                self.list_photos(directory)

    def list_photos(self, directory):
        self.file_list.Clear()
        sorted_list = sorted(os.listdir(directory))
        for file in sorted_list:
            if file.lower().endswith(('.jpg', '.jpeg', '.arw', '.nef', '.cr2', '.cr3','.rw2','.dng','.heic')):
                self.file_list.Append(file)

    def on_select_photo(self, event):
        selected_index = self.file_list.GetSelection()
        selected_file = self.file_list.GetString(selected_index)
        directory = self.input_box.GetValue()
        file_path = os.path.join(directory, selected_file)

        gps_info = self.get_gps_info(file_path)
        if gps_info:
            latitude, longitude = gps_info
            self.show_map(latitude, longitude)
            self.get_exiftool_cityinfo(file_path)
        else:
            wx.MessageBox("未找到 GPS 信息", "错误", wx.OK | wx.ICON_ERROR)

    def get_gps_info(self, image_path):
        """从照片的 EXIF 中提取 GPS 信息"""
        print()
        print(f'文件名：{image_path}')
        ext = os.path.splitext(image_path)[1].lower()
        if ext in ['.jpg', '.jpeg']:
            #image = Image.open(image_path)
            #exif_data = image._getexif()
            #datetimeoriginal = self.get_exif_datetime_original(exif_data)
           # if datetimeoriginal != None:
                #print(f'拍摄日期：{datetimeoriginal}', end='')
            #gps_info = self.extract_gps_from_exif(exif_data)
            gps_info = self.get_exif_info(image_path)
        elif  ext in ['.arw', '.nef', '.dng']:
            gps_info = self.extract_gps_from_raw(image_path)
        else:
            # cr2,cr3,rw2,heic 使用exiftool
            gps_info = self.get_exif_info(image_path)
        return gps_info
    # 获得拍摄日期
    def get_exif_datetime_original(self,exif_data):
        # 打开图像文件
        #image = Image.open(image_path)

        # 获取EXIF信息
        #exif_data = image._getexif()

        # 找到和打印拍摄日期
        if exif_data is not None:
            exif_uniquecameramodel = ''
            exif_make = ''
            exif_model = ''
            for tag_id, value in exif_data.items():
                tag = TAGS.get(tag_id, tag_id)
                if tag == 'Make':
                    exif_make = value
                elif  tag == 'Model':
                    exif_model = value
                elif tag == ('UniqueCameraModel'):
                    exif_uniquecameramodel = value

            make_string = f' {exif_make} {exif_model} {exif_uniquecameramodel} '
            print(make_string , end='')

            for tag_id, value in exif_data.items():
                tag = TAGS.get(tag_id, tag_id)
                if tag == 'DateTimeOriginal':
                    return value
        return None

    def extract_gps_from_exif(self, exif_data):
        """从 EXIF 数据中提取 GPS 信息"""
        if not exif_data:
            return None

        for tag_id, value in exif_data.items():
            tag = TAGS.get(tag_id, tag_id)
            #print(tag_id,tag)
            if tag == 'GPSInfo':
                if not value:
                    #print("my_dict 是一个空字典")
                    return None
                else:
                    #print('------v',value)
                    return self.parse_gps_info(value)
        return None

    def extract_gps_from_raw000(self, image_path):
        """从 RAW 格式图像提取 GPS 信息"""
        with rawpy.imread(image_path) as raw:
            # 使用 raw.exif 获取 EXIF 数据
            exif_data = raw.exif
            gps_info = None
            for tag_id, value in exif_data.items():
                tag_name = TAGS.get(tag_id, tag_id)
                if tag_name == 'GPSInfo':
                    if not value:
                        # print("my_dict 是一个空字典")
                        return None
                    else:
                        print(value)
                        gps_info = value
                        return self.parse_gps_info(value)

                    #break
            #return self.parse_gps_info(gps_info) if gps_info else None
            return None

    def extract_gps_from_raw(self, image_path):
        with open(image_path, 'rb') as image_file:
            tags = exifread.process_file(image_file)
            # 获取 GPS 信息
            gps_info = {}
            exif_make = tags['Image Make']
            exif_model = tags['Image Model']
            make_string = f'{exif_make}  {exif_model}'
            if 'Image UniqueCameraModel' in tags:
              exif_uniquecameramodel = tags['Image UniqueCameraModel']
              make_string = make_string + f' {exif_uniquecameramodel}'
            print(make_string,end='')
            if 'EXIF DateTimeOriginal' in tags:
                time_original = tags['EXIF DateTimeOriginal']
                print(f' 拍摄日期：{time_original}', end='')
            if 'GPS GPSLatitude' in tags and 'GPS GPSLongitude' in tags:
                gps_info['Latitude'] = tags['GPS GPSLatitude']
                gps_info['Longitude'] = tags['GPS GPSLongitude']
                gps_info['LatitudeRef'] = tags.get('GPS GPSLatitudeRef', None)
                gps_info['LongitudeRef'] = tags.get('GPS GPSLongitudeRef', None)
                #print('=====',gps_info['Latitude'],gps_info['Longitude'],gps_info['LatitudeRef'],gps_info['LongitudeRef'])
                # 处理 GPS 坐标
                latitude = self.convert_to_degrees(gps_info['Latitude'], gps_info['LatitudeRef'])
                longitude = self.convert_to_degrees(gps_info['Longitude'], gps_info['LongitudeRef'])

                #return {'Latitude': latitude, 'Longitude': longitude}
                return latitude, longitude
            else:
                return None

    def convert_to_degrees(self,value, ref):
        # 将度分秒转换为十进制度
        degrees = value.values[0] + (value.values[1] / 60.0) + (value.values[2] / 3600.0)
        if ref.values != 'N' and ref.values != 'E':
            degrees = -degrees
        return degrees

    def get_exif_info(self, file_path):
        try:
            # 取完整的 EXIF 信息
            #result = subprocess.check_output(["exiftool", file_path], universal_newlines=True)

            # 字段名替换字典
            field_replacements = {
                "Media Create Date": "\n媒体建立时间",
                "Date/Time Original": "\n拍摄时间",
                "File Modification Date/Time": "\n文件修改时间",
                "Lens ID": "镜头型号",
                "Lens Make": "镜头制造商",
                "Android Make": "手机制造商",
                "Make ": "设备制造商 ",
                "Camera Model Name": "设备型号",
                "Lens Model": "镜头型号",
                "Lens Type": "镜头类型"
            }
            # 替换提示为中文
            #for en_field, zh_field in field_replacements.items():
            #    result = result.replace(en_field, zh_field)

            # 创建 ExifTool 对象
            x1 = '1'  # 假设没有 GPS 信息
            with exiftool.ExifToolHelper() as et:
                metadata_list = et.get_metadata(file_path)
                if isinstance(metadata_list, list):
                    exif_make = ''
                    exif_model = ''
                    for metadata in metadata_list:
                        if 'EXIF:Make' in metadata:
                            exif_make = metadata['EXIF:Make']
                        if 'EXIF:Model' in metadata:
                            exif_model = metadata['EXIF:Model']
                        make_string = f' {exif_make} {exif_model} '
                        if 'EXIF:UniqueCameraModel' in metadata:
                           exif_uniquecameramodel = metadata['EXIF:UniqueCameraModel']
                           make_string = make_string + f' {exif_uniquecameramodel} '

                        print(make_string ,end='')

                        #print(metadata)
                        time_original = metadata.get("EXIF:DateTimeOriginal")
                        OffsetTime = metadata.get("EXIF:OffsetTime")
                        OffsetTimeOriginal = metadata.get("EXIF:OffsetTimeOriginal")
                        #FileModifyDate = metadata.get("File:FileModifyDate")
                        FileModifyDate = os.path.getmtime(file_path)
                        #FileModifyDate = datetime.fromtimestamp(FileModifyDate)

                        #if time_original == None:
                            # 文件没有拍照日期，不修改gps信息
                            #time_original = FileModifyDate
                            #print("==",time_original, OffsetTime, OffsetTimeOriginal, FileModifyDate)
                        #else:
                            #print(time_original,OffsetTime,OffsetTimeOriginal,FileModifyDate)

                        err,gps_latitude, gps_longitude, gps_latitude_ref, gps_longitude_ref = self.extract_gps(metadata,file_path)
                        if err == '0':
                            x1 = '1'
                            break  # 找到第一个有效的 GPS 信息就退出
                        if gps_latitude and gps_longitude:
                            x1 = '0'
                            break  # 找到第一个有效的 GPS 信息就退出

            # 如果有 GPS 信息，处理坐标
            gpsif = x1
            if x1 == '0':
                print(f'拍摄日期：{time_original}', end='')
                latitude = self.convert_to_degrees2(gps_latitude)
                longitude = self.convert_to_degrees2(gps_longitude)

                # 根据参考方向调整坐标值
                if gps_latitude_ref == "S":
                    latitude = -latitude
                if gps_longitude_ref == "W":
                    longitude = -longitude
                #print(f'该文件原有GPS信息：{longitude},{latitude}')
                return latitude, longitude
            else:
                #latitude = ''
                #longitude = ''
                return None
            # 设置 EXIF 文本框的值
            #print(result)
        except subprocess.CalledProcessError as e:
            # 捕获异常并设置错误信息
            print(f"获取 EXIF 信息时出错: {e}")
            return None
        except Exception as ex:
            # 捕获其他异常
            print(f"发生错误: {ex}")
            return None

    # 将 GPS 坐标转换为浮点数
    def convert_to_degrees2(self, value):
        # 检查输入的值是否为浮点数或整数
        if isinstance(value, (float, int)):
            return value  # 直接返回浮点数或整数
        # 检查输入的值是否为字符串
        elif isinstance(value, str):
            # 从字符串中解析出度、分、秒
            parts = value.split(' ')
            d = float(parts[0])  # 解析度
            m = float(parts[1])  # 解析分
            s = float(parts[2])  # 解析秒
            # 将度、分、秒转换为浮点数表示的度
            return d + (m / 60.0) + (s / 3600.0)
        # 检查输入的值是否为列表
        elif isinstance(value, list):
            d, m, s = value  # 解包列表中的度、分、秒
            # 将度、分、秒转换为浮点数表示的度
            return d + (m / 60.0) + (s / 3600.0)
        else:
            # 如果输入值的格式不正确，抛出异常
            raise ValueError("无法解析的 GPS 坐标格式")

    # 提取 GPS 信息的函数
    def extract_gps(self,metadata,file_path):
        #print(metadata)
        if "EXIF:GPSLatitude" in metadata:
            return (
                '1',
                metadata.get("EXIF:GPSLatitude"),
                metadata.get("EXIF:GPSLongitude"),
                metadata.get("EXIF:GPSLatitudeRef"),
                metadata.get("EXIF:GPSLongitudeRef")
            )
        else:
            return '0','','','',''


    def parse_gps_info(self, gps_info):
        """解析 GPS 信息"""
        lat = gps_info.get(2, (0, 0, 0))  # 纬度
        lat_ref = gps_info.get(3, 'N')
        lon = gps_info.get(4, (0, 0, 0))  # 经度
        lon_ref = gps_info.get(1, 'E')
        #print(lat_ref,lon_ref)
        # 将度分秒转换为十进制度
        latitude = lat[0] + lat[1] / 60 + lat[2] / 3600
        longitude = lon[0] + lon[1] / 60 + lon[2] / 3600

        # 计算分数
        # 使用分割操作将字符串分成分子和分母
        # 获取分子和分母
        numerator = latitude.numerator
        denominator = latitude.denominator
        latitude = numerator/denominator #Fraction(numerator, denominator)
        numerator = longitude.numerator
        denominator = longitude.denominator
        longitude = numerator/denominator #Fraction(numerator, denominator)

        #print(numerator, denominator)
        #print(latitude, longitude,type(latitude))
        if lat_ref == 'S':
            latitude = -latitude
        if lon_ref == 'W':
            longitude = -longitude

        return latitude, longitude

    def show_map(self, latitude, longitude):
        gd_appkey = gd_config.gd_api_key
        size = "800*500"
        zoom = "13"
        text = "显示文字"
        map_url = (f"https://restapi.amap.com/v3/staticmap?"
                   f"location={longitude},{latitude}&size={size}&zoom={zoom}"
                   f"&markers=mid,,A:{longitude},{latitude}&key={gd_appkey}")
        print(f' 坐标：{latitude},{longitude}')
        # 转换为 GCJ-02 坐标
        url = f'https://restapi.amap.com/v3/assistant/coordinate/convert?key={gd_appkey}&locations={longitude},{latitude}&coordsys=gps&output=json'
        #print(url)
        response = requests.get(url)
        #print(response)
        if response.status_code == 200:
            data = json.loads(response.text)
            if data['status'] == '1':
                # 转换后的高德坐标
                # {"status":"1","info":"ok","infocode":"10000","locations":"117.163480631511,34.228663194445"}
                amap_location = data['locations'] #[0]
                # 117.163480631511,34.228663194445
                #print(f"高德坐标: {amap_location}")

                # 根据参考方向调整坐标值
                #if gps_latitude_ref == "S":
                    #latitude = -latitude
                #if gps_longitude_ref == "W":
                   # longitude = -longitude

                # 使用高德地图API将 GPS 坐标转换为城市名称
                url = f"https://restapi.amap.com/v3/geocode/regeo?output=json&location={amap_location}&key={gd_appkey}&radius=1000&extensions=all"
                response = requests.get(url)
                data = response.json()

                # 提取城市名称
                if data.get("status") == "1" and "regeocode" in data:
                    address_component = data["regeocode"].get("addressComponent", {})
                    city = address_component.get("city", "")
                    province = address_component.get("province", "")
                    district = address_component.get("district", "")
                    country = address_component.get("country", "")
                    township = address_component.get("township", "")
                    street = address_component.get("streetNumber", {}).get("street", "")

                    if city:
                        # 添加拍摄位置到结果中
                        result = f" 拍摄于: {country}, {province}, {city}, {district}, {street}, {township} "
                        print(result)

                # 地图显示
                map_url = (f"https://restapi.amap.com/v3/staticmap?"
                           f"location={amap_location}&size={size}&zoom={zoom}"
                           f"&markers=mid,,A:{amap_location}&key={gd_appkey}")
            #else:
                #print(f"错误信息: {data['info']}")
        #else:
            #print("请求失败")


        #map_url = (f"https://restapi.amap.com/v3/staticmap?"
        #           f"location={longitude},{latitude}&size=800*400&zoom=14"
        #           f"&markers=mid,,A:{longitude},{latitude}&key={gd_appkey}")
        #print(map_url)
        response = self.map_window.LoadURL(map_url)
        # {"status": "0", "info": "UNKNOWN_ERROR", "infocode": "20003"}
        #print(response)
        #self.map_window.SetPage(f'''
        #<html>
        #  <body>
        #    <h1>地图</h1>
        #    <img src="{map_url}" width="600" height="400">
        #  </body>
        #</html>
        #''')

    def get_exiftool_cityinfo(self,image_file_path):
        # 要处理的图像文件路径
        #image_file_path = '/Volumes/ssknvme512/download/20241103/DSC03400.JPG'

        # 构建 ExifTool 命令
        command = ['exiftool', '-api', 'geolocation', '-geolocation*', image_file_path]

        # 执行命令并捕获输出
        try:
            result = subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            #print("ExifTool 输出：")
            # print(result.stdout)  # 输出结果
            output = result.stdout
            # 使用正则表达式提取每一行的值
            geolocation_data = {}
            for line in output.splitlines():
                match = re.match(r'(.+?):\s*(.+)', line)  # 匹配 "键 : 值" 格式
                if match:
                    key = match.group(1).strip()
                    value = match.group(2).strip()
                    geolocation_data[key] = value

            # 打印提取的值
            #print("\n提取的地理位置信息：")
            citylist = []
            for key, value in geolocation_data.items():
                #print(f"{key}: {value}")
                citylist.append(value)
            city_string = f'国家：{citylist[4]},省：{citylist[1]},市：{citylist[2]},城市：{citylist[0]}'
            print(city_string)
        except subprocess.CalledProcessError as e:
            print(f"执行命令时出错: {e.stderr}")  # 捕获并打印错误信息
        except Exception as e:
            print(f"发生其他错误: {e}")

if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFramemap()
    app.MainLoop()